#include<iostream>

#include<stdio.h>

#include<unistd.h>

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

#include<string.h>

#include<assert.h>

using namespace std;

#define SIZE 1024

#define FLUSH_NOW 1

#define FLUSH_LINE 2

#define FLUSH_ALL 4

#define FILE_MODE 0666

//int _fflush(_FILE *stream);

struct _FILE
{
    int _fd = 0;
    int _flag = FLUSH_ALL;
    char _outbuffer[SIZE] = {0};
    int _out_pos = 0;
};

int _fflush(_FILE *stream);

_FILE *_fopen(const char *path, const char *mode)
{
    assert(path);
    assert(mode);

    int fd = -1;
    if(!strcmp(mode, "w"))
    {
        fd = open(path, O_WRONLY|O_CREAT|O_TRUNC, FILE_MODE);
    }
    else if(!strcmp(mode, "a"))
    {
        fd = open(path, O_WRONLY|O_CREAT|O_APPEND, FILE_MODE);
    }
    else if(!strcmp(mode, "r"))
    {
        fd = open(path, O_RDONLY);
    }

    _FILE *newfile = new _FILE;
    newfile->_fd = fd;
    return newfile;
}

int _fclose(_FILE *fp)
{
    _fflush(fp);
    close(fp->_fd);
    delete fp;
    return 0;
}

size_t _fwrite(const void *ptr, size_t size, size_t nmemb, _FILE *stream)
{
    memcpy(&stream->_outbuffer[stream->_out_pos], ptr, size * nmemb);
    stream->_out_pos += size * nmemb;

    if(stream->_flag == FLUSH_NOW)
    {
        write(stream->_fd, stream->_outbuffer, stream->_out_pos);
        stream->_out_pos = 0;
    }
    else if(stream->_flag == FLUSH_LINE)
    {
        if(stream->_outbuffer[stream->_out_pos - 1] == '\n')
        {
            write(stream->_fd, stream->_outbuffer, stream->_out_pos);
            stream->_out_pos = 0;
        }
    }
    else if(stream->_flag == FLUSH_ALL)
    {
        if(stream->_out_pos == SIZE)
        {
            write(stream->_fd, stream->_outbuffer, stream->_out_pos);
            stream->_out_pos = 0;
        }
    }

    return nmemb;
}

int _fflush(_FILE *stream)
{
    write(stream->_fd, stream->_outbuffer, stream->_out_pos);
    stream->_out_pos = 0;

    return 0;
}

int main()
{
    _FILE *fp = _fopen("log.txt", "a");

    _fwrite("hello world\n", sizeof(char), strlen("hello world\n"), fp);

    close(fp->_fd);

    //_fclose(fp);
    return 0;
}
